/* 
 * File: Vertices
 * Created: 15-JUN-2011
 * Author: Colin Gall-McDaid
 * 
 * Description: Vertices helper class. Holds the vertices and indices (if used) to
 * be used for rendering. Also cleans up afterwards.
 */
package com.gallsoft.games.framework.gl;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
//import java.nio.FloatBuffer;              // FloatBuffer bug workaround
import java.nio.IntBuffer;
import java.nio.ShortBuffer;

import javax.microedition.khronos.opengles.GL10;

import com.gallsoft.games.framework.impl.GLGraphics;


public class Vertices {

    private final GLGraphics glGraphics;
    private final boolean hasColor;
    private final boolean hasTexCoords;
    private final int vertexSize;
    //private final FloatBuffer vertices;   // FloatBuffer bug workaround
    private final IntBuffer vertices;       // FloatBuffer bug workaround
    private final ShortBuffer indices;
    private final int[] tmpBuffer;          // FloatBuffer bug workaround
    
    /**
     * Constructor.
     * 
     * @param glGraphics
     *              OpenGL graphics context
     * @param maxVertices
     *              max number of vertices
     * @param maxIndices
     *              max number of indices
     * @param hasColor
     *              do vertices have colour
     * @param hasTexCoords
     *              do vertices have a texture
     */
    public Vertices(GLGraphics glGraphics, int maxVertices, int maxIndices, boolean hasColor, boolean hasTexCoords) {
        this.glGraphics = glGraphics;
        this.hasColor = hasColor;
        this.hasTexCoords = hasTexCoords;
        this.vertexSize = (2 + (hasColor ? 4 : 0) + (hasTexCoords ? 2 : 0)) * 4;
        this.tmpBuffer = new int[maxVertices * vertexSize / 4];
        
        ByteBuffer buffer = ByteBuffer.allocateDirect(maxVertices * vertexSize);
        buffer.order(ByteOrder.nativeOrder());
        //vertices = buffer.asFloatBuffer();
        vertices = buffer.asIntBuffer();        // FloatBuffer bug workaround
        
        if (maxIndices > 0 ) {
            buffer = ByteBuffer.allocateDirect(maxIndices * Short.SIZE / 8);
            buffer.order(ByteOrder.nativeOrder());
            indices = buffer.asShortBuffer();        
        }
        else
            indices = null;
    }
    
    /**
     * Set the vertices
     * 
     * @param vertices
     *          list of vertices
     * @param offset
     *          vertice index start point
     * @param length
     *          number of vertices
     */
    public void setVertices(float[] vertices, int offset, int length) {
        this.vertices.clear();
        
        //this.vertices.put(vertices, offset, length);
        
        // FloatBuffer bug workaround
        int len = offset + length;
        for (int i = offset, j = 0; i < len; i++, j++)
            tmpBuffer[j] = Float.floatToRawIntBits(vertices[i]);            
        this.vertices.put(tmpBuffer, 0, length);
        
        this.vertices.flip();
    }
    
    /**
     * Set the indices
     * 
     * @param indices
     *          list of indices
     * @param offset
     *          indices index start point
     * @param length
     *          number of indices
     */
    public void setIndices(short[] indices, int offset, int length) {
        this.indices.clear();
        this.indices.put(indices, offset, length);
        this.indices.flip();
    }
    
    public void bind() {
        GL10 gl = glGraphics.getGL();
        
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        vertices.position(0);
        gl.glVertexPointer(2, GL10.GL_FLOAT, vertexSize, vertices);
        
        if (hasColor) {
            gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
            vertices.position(20);
            gl.glColorPointer(4, GL10.GL_FLOAT, vertexSize, vertices);
        }
        
        if (hasTexCoords) {
            gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
            vertices.position(hasColor ? 6 : 2);
            gl.glTexCoordPointer(2, GL10.GL_FLOAT, vertexSize, vertices);
        }        
    }
    
    public void unbind() {
        GL10 gl = glGraphics.getGL();
        
        if (hasTexCoords)
            gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
        
        if (hasColor)
            gl.glDisableClientState(GL10.GL_COLOR_ARRAY);
    }
    
    /**
     * Draw primitiveType (eg GL_TRIANGLES) using indices if provided
     * 
     * @param primitiveType
     *          primitive type to draw
     * @param offset
     *          position to start
     * @param numVertices
     *          number of vertices
     */
    public void draw(int primitiveType, int offset, int numVertices) {
        GL10 gl = glGraphics.getGL();
        
        if (indices != null) {
            indices.position(offset);
            gl.glDrawElements(primitiveType, numVertices, GL10.GL_UNSIGNED_SHORT, indices);
        }
        else {
            gl.glDrawArrays(primitiveType, offset, numVertices);
        }        
    }
}
